"""
订单库存预扣与备份（Redis）
"""
from typing import List, Tuple
import json
from utils.myredis import Mredis


def _stock_key(goods_id: int) -> str:
    return f"stock:goods:{goods_id}"


def _backup_key() -> str:
    return "order:backup"


def _ensure_init_stock(r: Mredis, goods_id: int):
    """
    若Redis中无库存，则从数据库初始化一次
    """
    key = _stock_key(goods_id)
    if not r.exists(key):
        # 懒加载DB
        from database.base import SessionLocal
        from models.goods_models import Goods
        db = SessionLocal()
        try:
            goods = db.query(Goods).filter(Goods.id == goods_id).first()
            stock = int(getattr(goods, "stock", 0) or 0) if goods else 0
        finally:
            db.close()
        r.set_str(key, str(stock))


def reserve_stock(order_no: str, goods_ids: List[int], quantities: List[int]) -> Tuple[bool, str]:
    """
    预扣库存：逐个商品扣减Redis库存。任一不足则回滚。
    成功会把订单放入备份队列。
    """
    r = Mredis()
    changed = []
    for gid, qty in zip(goods_ids, quantities):
        _ensure_init_stock(r, gid)
        # 原子性不强（简化实现），在当前单机和低并发场景可接受
        new_val = r.r.decrby(_stock_key(gid), int(qty))
        if new_val < 0:
            # 回滚已扣的
            for pgid, pqty in changed:
                r.r.incrby(_stock_key(pgid), int(pqty))
            return False, f"商品 {gid} 库存不足"
        changed.append((gid, qty))

    # 写入备份队列
    backup = {
        "order_no": order_no,
        "items": [{"goods_id": gid, "qty": qty} for gid, qty in zip(goods_ids, quantities)]
    }
    r.list_rpush(_backup_key(), json.dumps(backup, ensure_ascii=False))
    return True, "ok"


def restore_stock(order_no: str):
    """
    回滚库存（按备份信息）。用于取消或超时清理。
    """
    r = Mredis()
    # 简化：线性扫描备份列表找到该订单
    items = r.list_lrange(_backup_key(), 0, -1)
    target = None
    for it in items:
        try:
            data = json.loads(it.decode() if isinstance(it, (bytes, bytearray)) else it)
            if data.get("order_no") == order_no:
                target = it
                payload = data
                break
        except Exception:
            continue
    if target:
        for rec in payload.get("items", []):
            gid = int(rec.get("goods_id"))
            qty = int(rec.get("qty"))
            _ensure_init_stock(r, gid)
            r.r.incrby(_stock_key(gid), qty)
        r.list_del(_backup_key(), target)


def finish_order(order_no: str):
    """
    订单完成：删除备份记录（不再回滚）。
    """
    r = Mredis()
    items = r.list_lrange(_backup_key(), 0, -1)
    for it in items:
        try:
            data = json.loads(it.decode() if isinstance(it, (bytes, bytearray)) else it)
            if data.get("order_no") == order_no:
                r.list_del(_backup_key(), it)
                break
        except Exception:
            continue


